// /////////////////////////////////////////////////////////////////////////////
//
// Name:            ScriptManager.h
// Author:          Michael Bartsch (ZCCdark203)
//
// Desc :           Declaration of the EventManager class.
//
// License:         Copyright (C) 2009 Michael Bartsch and Contributors
//
//                  This program is free software: you can redistribute it
//                  and/or modify it under the terms of the zlib/libpng License.
//                  See main.cpp for conditions of distribution and use.
//
// /////////////////////////////////////////////////////////////////////////////

#ifndef __EVENTMANAGER_H__
#define __EVENTMANAGER_H__

// Include files
#include "../dependencies.h"
#include "ReferenceCounted.h"

// Typedefs
typedef sigslot::signal1<void*> EventSlot;


// EventManager class
//! The Event Manager is the central interface point to all event related functions of this program.
class EventManager : public IEventReceiver, public ReferenceCounted
{
public:

    // Initialisation and deinitialisation
    //! Constructor
    EventManager();
    //! Deconstructor
    ~EventManager();

    //! Initialises the EventManager.
    void init();
    //! Clears the EventManager.
    void clear();

    // Reference counting
    //! Increases the reference counter.
    //! @note This is a dummy function.
    void grab();
    //! Decreases the reference counter.
    //! @note This is a dummy function.
    void drop();

    // Methods
    //! Creates a new event group, a collection of events.
    //! @param groupName     Name of the event group.
    //! @return True if creation was successful, false if creation was a failure.
    bool createEventGroup(const std::string &groupName);
    //! Creates a new event slot in the given event group.
    //! @param groupName     Name of the event group.
    //! @param slotName      Name of the event slot.
    //! @return True if creation was successful, false if creation was a failure.
    bool createEventSlot(const std::string &groupName, const std::string &slotName);

    //! Connects a function to the given event slot.
    //! @param groupName     Name of the event group.
    //! @param slotName      Name of the event slot.
    //! @param t             Pointer to the object that will function as this-object when the
    //!                      connect function is called.
    //! @param m             Pointer to the function.
    template<typename T>
    bool connectEventSignal(const std::string &groupName, const std::string &slotName,
                            T *t, void (T::*m)(void*))
    {
        // Get the given event group.
        std::map<std::string, std::map<std::string, EventSlot> >::iterator itGroups;
        itGroups = mEvents.find(groupName);

        if(itGroups == mEvents.end())
          return false;

        std::map<std::string, EventSlot> &group = itGroups->second;

        // Get the given event slot.
        std::map<std::string, EventSlot>::iterator itSlots = group.find(slotName);

        if(itSlots == group.end())
         return false;

        cout << "Success!\n";
        EventSlot &signal = itSlots->second;

        // Connect to the signal.
        signal.connect(t, m);
        return true;
    };

    //! Disconnects a function from the given event slot.
    //! @param groupName     Name of the event group.
    //! @param slotName      Name of the event slot.
    //! @param t             Pointer to the object that will function as this-object when the
    //!                      connect function is called.
    template<typename T>
    bool disconnectEventSignal(const std::string &groupName, const std::string &slotName, T *t)
    {
        // Get the given event group.
        std::map<std::string, std::map<std::string, EventSlot> >::iterator itGroups;
        itGroups = mEvents.find(groupName);

        if(itGroups == mEvents.end())
          return false;

        std::map<std::string, EventSlot> &group = itGroups->second;

        // Get the given event slot.
        std::map<std::string, EventSlot>::iterator itSlots = group.find(slotName);

        if(itSlots == group.end())
         return false;

        EventSlot &signal = itSlots->second;

        // Disconnect from the signal.
        signal.disconnect(t);
        return true;
    };

    //! Emits an event to the given event slot.
    //! @param groupName     Name of the event group.
    //! @param slotName      Name of the event slot.
    //! @param p             Pointer to data which will be passed to all functions called.
    bool emitEvent(const std::string &groupName, const std::string &slotName, void* p = 0);

    //! Checks if the given key is down.
    bool getIsKeyDown(EKEY_CODE keyCode) const;
    //! Checks if the given key is up.
    bool getIsKeyUp(EKEY_CODE keyCode) const;

    //! Returns the X-coordinate of the mouse position.
    s32 getMouseX() const;
    //! Returns the Y-coordinate of the mouse position.
    s32 getMouseY() const;
    //! Returns the position of the mouse as a 2d vector.
    const vector2di& getMousePos() const;
    //! Gets the mouse wheel position.
    f32 getMouseWheel() const;

    //! Removes all event groups from the EventManager.
    void removeEventGroups();
    //! Removes all event slots from the given event group.
    //! @param groupName     Name of the event group.
    //! @return True if removal was successful, false if removal was a failure.
    bool removeEventSlots(const std::string &groupName);
    //! Removes the given event group from the Event Manager.
    //! @param groupName     Name of the event group to remove.
    //! @return True if removal was successful, false if removal was a failure.
    bool removeEventGroup(const std::string &groupName);
    //! Removes the given event slot from the given event group.
    //! @param groupName     Name of the event group.
    //! @param slotName      Name of the event slot to remove.
    //! @return True if removal was successful, false if removal was a failure.
    bool removeEventSlot(const std::string &groupName, const std::string &slotName);

    //! Handles the events sent by the Irrlicht engine.
    //! @note For internal use only!
    virtual bool OnEvent(const SEvent &event);

private:

    // Private initialisation and deinitialisation
    void generateKeyMap();

    // Members
    std::map<std::string, std::map<std::string, EventSlot> > mEvents;

    bool mKeyState[KEY_KEY_CODES_COUNT];
    std::map<EKEY_CODE, std::string> mKeyMap;

    vector2di mMousePos;
    f32 mMouseWheel;

};

#endif
